#include"rational.h"
#include<iostream>
using namespace std;

void Rational::canonize() const {
	if (den != 1) {
		unsigned long a = (num >= 0) ? num : -num;
		unsigned long b = den;
		while (b != 0) {
			a %= b;
			std::swap(a,b);
		}
		num = num / (long)a; // for some reason signed / unsigned gets cast to unsigned. I don't get it.
		den /= a;
	}
}

Rational::Rational (long a) : num(a), den(1) {}
	
Rational::Rational (long a, unsigned long b) : num(a), den(b ? b : 1) {}
	
Rational::Rational (Rational const & r) : num(r.num), den(r.den) {}
	
void Rational::swap(Rational & r) {
	std::swap(num , r.num);
	std::swap(den , r.den);
}

Rational & Rational::operator += (Rational const & r) {
	num = r.num * den + r.den * num;
	den = r.den * den;
	canonize();
	return *this;
}

Rational & Rational::operator -= (Rational const & r) {
	num = r.den * num - r.num * den;
	den = r.den * den;
	canonize();
	return *this;
}

Rational & Rational::operator *= (Rational const & r) {
	num *= r.num;
	den *= r.den;
	canonize();
	return *this;
}

Rational & Rational::operator /= (Rational const & r) {
	num *= (r.num >= 0) ? r.den : -r.den;
	den *= (r.num >= 0) ? r.num : -r.num;
	if (!den) throw "Division by zero";
	canonize();
	return *this;
}

Rational operator + (Rational const & r1, Rational const & r2) {
	Rational temp(r1);
	temp += r2;
	return temp;
}

Rational operator - (Rational const & r1, Rational const & r2) {
	Rational temp(r1);
	temp -= r2;
	return temp;
}

Rational operator - (Rational const & r) {
	Rational temp(0);
	temp -= r;
	return temp;
}


Rational operator * (Rational const & r1, Rational const & r2) {
	Rational temp(r1);
	temp *= r2;
	return temp;
}

Rational operator / (Rational const & r1, Rational const & r2) {
	Rational temp(r1);
	temp /= r2;
	return temp;
}

bool operator == (Rational const & r1, Rational const & r2) {
	return (r1.num == r2.num) && (r1.den == r2.den);
}
	
bool operator <= (Rational const & r1, Rational const & r2) {
	return ! (r2 < r1);
}
	
bool operator >= (Rational const & r1, Rational const & r2) {
	return ! (r1 < r2);
}
	
bool operator < (Rational const & r1, Rational const & r2) {
	return (r1.num * r2.den < r2.num * r1.den);
}
	
bool operator > (Rational const & r1, Rational const & r2) {
	return r2 < r1;
}
	
bool operator != (Rational const & r1, Rational const & r2) {
	return ! (r1 == r2);
}

Rational & Rational::operator ++ () {
	num += den;
	return *this;
}

Rational Rational::operator ++ (int) {
	Rational temp(*this);
	num += den;
	return temp;
}

ostream & operator << (ostream & c, Rational const & r) {
	return (r.den != 1) ? (c << r.num << "/" << r.den) : (c << r.num);
}

Rational::operator double () const {
	return (double)num / den;
}